package com.yami.shop.seckill.common.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.app.dto.ShopCartItemDto;
import com.yami.shop.bean.app.dto.ShopCartOrderDto;
import com.yami.shop.bean.app.dto.ShopCartOrderMergerDto;
import com.yami.shop.bean.event.PayManagerEvent;
import com.yami.shop.bean.model.PayInfo;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.dao.OrderMapper;
import com.yami.shop.dao.PayInfoMapper;
import com.yami.shop.seckill.common.dao.SeckillMapper;
import com.yami.shop.seckill.common.dao.SeckillOrderMapper;
import com.yami.shop.seckill.common.dao.SeckillSkuMapper;
import com.yami.shop.seckill.common.dto.SeckillOrderMergerDto;
import com.yami.shop.seckill.common.model.Seckill;
import com.yami.shop.seckill.common.model.SeckillOrder;
import com.yami.shop.seckill.common.service.SeckillOrderService;
import com.yami.shop.seckill.common.service.SeckillService;
import com.yami.shop.service.OrderService;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 秒杀订单
 *
 * @author LGH
 * @date 2019-08-28 09:36:59
 */
@Service
@AllArgsConstructor
public class SeckillOrderServiceImpl extends ServiceImpl<SeckillOrderMapper, SeckillOrder> implements SeckillOrderService {

    private final SeckillOrderMapper seckillOrderMapper;

    private final SeckillSkuMapper seckillSkuMapper;

    private final PayInfoMapper payInfoMapper;

    private final OrderMapper orderMapper;

    private final OrderService orderService;

    private final SeckillService seckillService;

    private final SeckillMapper seckillMapper;

    private final ApplicationEventPublisher eventPublisher;

    @Override
    @CachePut(cacheNames = "ConfirmSeckillOrderCache", key = "#userId")
    public SeckillOrderMergerDto putConfirmOrderCache(String userId, SeckillOrderMergerDto seckillOrderMergerDto) {
        return seckillOrderMergerDto;
    }

    @Override
    @Cacheable(cacheNames = "ConfirmSeckillOrderCache", key = "#userId")
    public SeckillOrderMergerDto getConfirmOrderCache(String userId) {
        return null;
    }

    @Override
    @CacheEvict(cacheNames = "ConfirmSeckillOrderCache", key = "#userId")
    public void removeConfirmOrderCache(String userId) {
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submit(ShopCartOrderMergerDto dto) {
        if (StrUtil.isNotBlank(dto.getLocale())) {
            LocaleContextHolder.setLocale(new Locale(dto.getLocale()));
        }
        ShopCartOrderDto shopCartOrderDto = dto.getShopCartOrders().get(0);
        ShopCartItemDto shopCartItemDto = shopCartOrderDto.getShopCartItemDiscounts().get(0).getShopCartItems().get(0);

        this.checkOrderProdNum(seckillService.getSeckillById(dto.getSeckillId()), dto.getUserId(), shopCartItemDto.getProdCount());

        // 更新秒杀sku库存，乐观锁
        if (seckillSkuMapper.updateStocks(dto.getSeckillSkuId(), shopCartItemDto.getProdCount()) != 1) {
            // 本商品已被秒杀完毕，下次记得早点来哟
            throw new YamiShopBindException("yami.seckill.finish");
        }
        String orderNumber = shopCartOrderDto.getOrderNumber();
        // 保存秒杀订单信息
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setCreateTime(new Date());
        seckillOrder.setOrderNumber(orderNumber);
        seckillOrder.setProdCount(shopCartItemDto.getProdCount());
        seckillOrder.setSeckillId(dto.getSeckillId());
        seckillOrder.setUserId(dto.getUserId());
        seckillOrder.setProdId(shopCartItemDto.getProdId());
        seckillOrder.setSeckillSkuId(dto.getSeckillSkuId());
        // 秒杀成功等待支付
        seckillOrder.setState(0);
        seckillOrderMapper.insert(seckillOrder);
        // 更新活动剩余库存
        if (seckillMapper.updateStocksById(dto.getSeckillId(), shopCartItemDto.getProdCount()) < 1) {
            // 本商品已被秒杀完毕，下次记得早点来哟
            throw new YamiShopBindException("yami.seckill.finish");
        }
        // 创建订单相关信息
        orderService.submit(dto);
        return orderNumber;
    }

    @Override
    public void checkOrderProdNum(Seckill seckill, String userId, int prodCount) {

        // 判断之前秒杀的商品有没有超过限制，-1表示商品不限制秒杀数量
        if (!Objects.equals(seckill.getMaxNum(), -1)) {
            int dbCount = seckillOrderMapper.selectNumByUser(seckill.getSeckillId(), seckill.getProdId(), userId);
            if (seckill.getMaxNum() < prodCount + dbCount) {
                // 本次秒杀商品限购
                String limitMsg = I18nMessage.getMessage("yami.seckill.limit.shop");
                String message = I18nMessage.getMessage("yami.seckill.num");
                throw new YamiShopBindException(limitMsg + seckill.getMaxNum() + message);
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrderUnpayOrderByTime() {
        // 查询出微信or支付宝支付并且为二维码支付的，失效掉对应支付二维码
        List<PayInfo> filterPayInfo = payInfoMapper.listByPayTypeAndTime();
        Date now = new Date();
        List<Long> skuIds = seckillSkuMapper.listSkuIds();
        List<String> keys = new ArrayList<>();
        for (Long skuId : skuIds) {
            keys.add(Constant.SECKILL_SKU_STOCKS_PREFIX + skuId);
        }
        // 还原库存
        seckillSkuMapper.returnStocks(now);
        // 还原库存
        seckillMapper.returnStocks(now);
        // 修改订单状态
        orderMapper.cancelSeckillOrderByTime(now);
        // 将秒杀订单状态改为失效状态
        seckillOrderMapper.cancelUnpayOrder();
        // 删除库存的缓存
        RedisUtil.del(keys);
        eventPublisher.publishEvent(new PayManagerEvent(filterPayInfo));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelUnpayOrderByOrderNumber(String orderNumber) {
        SeckillOrder seckillOrder = seckillOrderMapper.selectOne(Wrappers.lambdaQuery(SeckillOrder.class)
                .eq(SeckillOrder::getOrderNumber, orderNumber));
        if(Objects.isNull(seckillOrder)){
            return;
        }
        // 还原秒杀库存
        seckillSkuMapper.returnStocksByOrderNumber(orderNumber);

        // 还原秒杀库存
        seckillMapper.returnStocksByOrderNumber(orderNumber);

        seckillOrderMapper.cancelUnpayOrderByOrderNumber(orderNumber);

        // 清除库存的缓存
        RedisUtil.del(Constant.SECKILL_SKU_STOCKS_PREFIX + seckillOrder.getSeckillSkuId());
    }
}
